package org.particlethink.service.impl;

import org.particlethink.auth.DefaultUser;
import org.particlethink.entry.OrderStatus;
import org.particlethink.entry.PlanTyp;
import org.particlethink.exception.NoPermissionException;
import org.particlethink.exception.OrderRefuseException;
import org.particlethink.exception.ParameterException;
import org.particlethink.exception.StatusException;
import org.particlethink.mapper.DeliverMapper;
import org.particlethink.mapper.OrderMapper;
import org.particlethink.mapper.PlanMaterialMapper;
import org.particlethink.model.Deliver;
import org.particlethink.model.Order;
import org.particlethink.model.PlanMaterial;
import org.particlethink.service.CanUpdateOrder;
import org.particlethink.service.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private DeliverMapper deliverMapper;
    @Autowired
    private PlanMaterialMapper planMaterialMapper;

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Override
    public void refuse(Integer orderId, String refuseReason, CanUpdateOrder canUpdateOrder) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();

        Order order = this.orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new ParameterException();
        }

        if (!(order.canRefuse() || order.canCancel())) {
            throw new StatusException();
        }

        if (!canUpdateOrder.canUpdateOrder(order)) {
            throw new NoPermissionException();
        }
        logger.debug("{}{}", order.getId(), order.getStatus());

        order.setStatus(OrderStatus.Refuse);
        order.setRefuseDate(new Date());
        order.setRemark(refuseReason);
        order.setRefuseUserType(defaultUser.findRole());
        order.setRefuseUserId(defaultUser.getUserId());

        this.orderMapper.updateByPrimaryKey(order);
    }


    public void complete(Order order, List<Deliver> delivers) {
//      进行中的订单显示此按钮。终止后，已发货的子订单将不受影响；未发货的订单将终止发货，状态不受影响。
        if (delivers.stream().allMatch(Deliver::isComplete)) {
            order.setStatus(OrderStatus.Done);
        }
        this.orderMapper.updateByPrimaryKeySelective(order);


//        delivers.stream().map(Deliver::get)
        List<PlanMaterial> planMaterials = this.planMaterialMapper.selectByOrderID(order.getId());


        if (delivers.isEmpty()) {
            planMaterials = planMaterials.stream().map(planMaterial -> {
                planMaterial.setExpectNum(0);
                return planMaterial;
            }).collect(Collectors.toList());
            this.planMaterialMapper.updateExpectNum(planMaterials);
            return;
        }

//        Map<Integer, PlanMaterial> planMaterialMap = ListUtilsKt.map(planMaterials, PlanMaterial::getMaterialId);
        List<Integer> deliverIds = delivers.stream().map(Deliver::getId).collect(Collectors.toList());

        List<PlanMaterial> deliverMaterials = this.planMaterialMapper.selectByPlanIDsAndTyp(deliverIds, PlanTyp.Deliver);


        Map<Integer, Integer> materialId2getExpectNumMap = deliverMaterials.stream().collect(Collectors.groupingBy(PlanMaterial::getMaterialId, Collectors.summingInt(PlanMaterial::getExpectNum)));
        planMaterials = planMaterials.stream().map(planMaterial -> {
            planMaterial.setExpectNum(materialId2getExpectNumMap.get(planMaterial.getMaterialId()));
            return planMaterial;
        }).collect(Collectors.toList());

        if (planMaterials.isEmpty()) {
            return;
        }


        this.planMaterialMapper.updateExpectNum(planMaterials);
    }
}
